home *** CD-ROM | disk | FTP | other *** search
/ PC World 2002 September / PCWorld_2002-09_cd.bin / Software / Vyzkuste / httrack / httrack-3.20RC4.exe / {app} / src / htsftp.c < prev    next >
C/C++ Source or Header  |  2002-07-09  |  33KB  |  1,136 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: basic FTP protocol manager                             */
  34. /* Author: Xavier Roche                                         */
  35. /* ------------------------------------------------------------ */
  36.  
  37. // Gestion protocole ftp
  38. // Version .05 (01/2000)
  39.  
  40. #include "htsftp.h"
  41.  
  42. #include "htsglobal.h"
  43. #include "htsbase.h"
  44. #include "htsnet.h"
  45. #include "htsthread.h"
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #if HTS_WIN
  50. #else
  51. //inet_ntoa
  52. #include <arpa/inet.h>
  53. #endif
  54.  
  55. #if HTS_WIN
  56. #ifndef __cplusplus
  57. // DOS
  58. #include <process.h>    /* _beginthread, _endthread */
  59. #endif
  60. #endif
  61.  
  62. // ftp mode passif
  63. // #if HTS_INET6==0
  64. #define FTP_PASV 1
  65. // #else
  66. // no passive mode for v6
  67. // #define FTP_PASV 0
  68. // #endif
  69.  
  70. #define FTP_DEBUG 0
  71. //#define FORK_DEBUG 0
  72.  
  73. #define FTP_STATUS_READY 1001
  74.  
  75. #if USE_BEGINTHREAD
  76. /*
  77. #ifdef __cplusplus
  78. // C++ -> Shell
  79. UINT back_launch_ftp( LPVOID pP ) {
  80.   lien_back* back=(lien_back*) pP;
  81.   if (back == NULL) {
  82.     //back->status=FTP_STATUS_READY;    // fini
  83.     //back->r.statuscode=-1;
  84.     return -1;
  85.   }
  86.   
  87.   // lancer ftp
  88.   run_launch_ftp(back);
  89.   // prΩt
  90.   back->status=0;
  91.  
  92.   return 0;    // thread completed successfully
  93. }
  94. #else
  95. */
  96. PTHREAD_TYPE back_launch_ftp( void* pP ) {
  97.   lien_back* back=(lien_back*) pP;
  98.   if (back == NULL) {
  99.     //back->status=FTP_STATUS_READY;    // fini
  100.     //back->r.statuscode=-1;
  101. #if FTP_DEBUG
  102.     printf("[ftp error: no args]\n");
  103. #endif
  104.     return PTHREAD_RETURN;
  105.   }
  106.  
  107.   /* Initialize */ 
  108.   hts_init();
  109.  
  110.   // lancer ftp
  111. #if FTP_DEBUG
  112.   printf("[Launching main ftp routine]\n");
  113. #endif
  114.   run_launch_ftp(back);
  115.   // prΩt
  116.   back->status=0;
  117.   
  118.   /* Uninitialize */
  119.   hts_uninit();
  120.   return PTHREAD_RETURN;
  121. }
  122. /*#endif*/
  123. // lancer en back
  124. void launch_ftp(lien_back* back) {
  125. /*
  126. #ifdef __cplusplus
  127.   // C++ -> Shell
  128.   AfxBeginThread(back_launch_ftp,(LPVOID) back);
  129. #else
  130. */
  131.   // DOS
  132. #if FTP_DEBUG
  133.   printf("[Launching main ftp thread]\n");
  134. #endif
  135.   _beginthread(back_launch_ftp, 0, (void*) back);
  136. /*#endif*/
  137. }
  138.  
  139. #else
  140. // Unix sans pthread
  141. int back_launch_ftp(lien_back* back) {
  142.   // lancer ftp
  143.   run_launch_ftp(back);
  144.   // prΩt
  145.   back->status=0;
  146.   return 0;
  147. }
  148. void launch_ftp(lien_back* back,char* path,char* exec) {
  149.   FILE* fp = fopen(fconv(path),"wb");
  150.   if (fp) {
  151.     char _args[8][256];
  152.     char *args[8];
  153.     fclose(fp); fp=NULL;
  154.     
  155.     strcpy(_args[0],exec);
  156.     strcpy(_args[1],"-#R");
  157.     strcpy(_args[2],back->url_adr);
  158.     strcpy(_args[3],back->url_fil);
  159.     strcpy(_args[4],back->url_sav);
  160.     strcpy(_args[5],path);
  161.     //strcpy(_args[6],"");
  162.     args[0]=_args[0];
  163.     args[1]=_args[1];
  164.     args[2]=_args[2];
  165.     args[3]=_args[3];
  166.     args[4]=_args[4];
  167.     args[5]=_args[5];
  168.     args[6]=NULL;
  169.     switch (fork()) {    // note: vfork dΘconne un max'
  170.     case -1: printf("Can not vfork() process\n"); break;
  171.     case 0: 
  172.       if (execvp(args[0],args)==-1) {
  173.         fp=fopen(fconv(path),"wb");
  174.         if (fp) {
  175.           fprintf(fp,"-1 unable to launch %s",args[0]);
  176.           fclose(fp); fp=NULL;
  177.           rename(path,concat(path,".ok"));
  178.         } else remove(path);
  179.       }
  180.       _exit(0);    // exit 'propre'
  181.       break;
  182.     default:  // parent
  183.       // bah on fait rien..
  184.       break;         
  185.     }
  186.   }
  187. }
  188. #endif
  189.  
  190. // pour l'arrΩt du ftp
  191. #ifdef _WIN32
  192. #define _T_SOC_close(soc)  closesocket(soc); soc=INVALID_SOCKET;
  193. #else
  194. #define _T_SOC_close(soc)  close(soc); soc=INVALID_SOCKET;
  195. #endif
  196. #define _HALT_FTP { \
  197.   if ( soc_ctl     != INVALID_SOCKET ) _T_SOC_close(soc_ctl); \
  198.   if ( soc_servdat != INVALID_SOCKET ) _T_SOC_close(soc_servdat); \
  199.   if ( soc_dat     != INVALID_SOCKET ) _T_SOC_close(soc_dat); \
  200. }
  201. #define _CHECK_HALT_FTP \
  202.   if (stop_ftp(back)) { \
  203.   _HALT_FTP \
  204.   return 0; \
  205.   }
  206.  
  207. // la vΘritable fonction une fois lancΘes les routines thread/fork
  208. int run_launch_ftp(lien_back* back) {
  209.   char user[256]="anonymous";
  210.   char pass[256]="user@";
  211.   char line_retr[2048];
  212.   int port=21;
  213. #if FTP_PASV
  214.   int port_pasv=0;
  215. #endif
  216.   char adr_ip[1024];
  217.   char *adr,*real_adr;
  218.   char* ftp_filename="";
  219.   int timeout = 300;    // timeout
  220.   int timeout_onfly=8;  // attente rΘponse supplΘmentaire
  221.   int transfer_list=0;  // directory
  222.   int rest_understood=0;  // rest command understood
  223.   t_fullhostent fullhostent_buffer;   // buffer pour resolver
  224.   //
  225.   T_SOC soc_ctl=INVALID_SOCKET;
  226.   T_SOC soc_servdat=INVALID_SOCKET;
  227.   T_SOC soc_dat=INVALID_SOCKET;
  228.   //
  229.   SOCaddr server_data;
  230.   int server_data_size=sizeof(server_data);
  231.   //
  232.   line_retr[0]=adr_ip[0]='\0';
  233.   
  234.   timeout=300;
  235.   
  236.   // effacer
  237.   strcpy(back->r.msg,"");
  238.   back->r.statuscode=0;
  239.   back->r.size=0;
  240.   
  241.   // rΘcupΘrer user et pass si prΘsents, et sauter user:id@ dans adr
  242.   real_adr = strchr(back->url_adr,':');
  243.   if (real_adr) real_adr++;
  244.   else real_adr=back->url_adr;
  245.   while(*real_adr=='/') real_adr++;    // sauter /
  246.   if ( (adr = jump_identification(real_adr)) != real_adr) {  // user
  247.     int i=-1;
  248.     pass[0]='\0';
  249.     do {
  250.       i++;
  251.       user[i]=real_adr[i];
  252.     } while( (real_adr[i]!=':') && (real_adr[i]) );
  253.     user[i]='\0';
  254.     if (real_adr[i]==':') {    // pass
  255.       int j=-1;
  256.       i++;  // oui on saute aussi le :
  257.       do {
  258.         j++;
  259.         pass[j]=real_adr[i+j];
  260.       } while( ((&real_adr[i+j+1]) < adr) && (real_adr[i+j]) );
  261.       pass[j]='\0';
  262.     }
  263.   }
  264.   
  265.   // Calculer RETR <nom>
  266.   {
  267.     char* a;
  268.     a=back->url_fil + strlen(back->url_fil)-1;
  269.     while( (a > back->url_fil) && (*a!='/')) a--;
  270.     if (*a == '/') {    // ok repΘrΘ
  271.       a++;    // sauter /
  272.       ftp_filename=a;
  273.       if (strnotempty(a)) {
  274.         char* ua=unescape_http(a);
  275.         if (
  276.           (strchr(ua, ' '))
  277.           ||
  278.           (strchr(ua, '\"'))
  279.           ||
  280.           (strchr(ua, '\''))
  281.           ) {
  282.           sprintf(line_retr,"RETR \"%s\"",ua);
  283.         } else {      /* Regular one */
  284.           sprintf(line_retr,"RETR %s",ua);
  285.         }
  286.       } else {
  287.         transfer_list=1;
  288.         sprintf(line_retr,"LIST -A");
  289.       }
  290.     } else {
  291.       strcpy(back->r.msg,"Unexpected PORT error");
  292.       back->status=FTP_STATUS_READY;    // fini
  293.       back->r.statuscode=-1;
  294.     }
  295.   }
  296.   
  297. #if FTP_DEBUG
  298.   printf("Connecting to %s...\n",adr);
  299. #endif
  300.   
  301.   // connexion
  302.   {
  303.     SOCaddr server;
  304.     int server_size=sizeof(server);
  305.     t_hostent* hp;    
  306.     char * a;
  307.     char _adr[256];
  308.     _adr[0]='\0';
  309.     //T_SOC soc_ctl;
  310.     // effacer structure
  311.     memset(&server, 0, sizeof(server));
  312.     
  313.     // port
  314.     a=strchr(adr,':');    // port
  315.     if (a) {
  316.       sscanf(a+1,"%d",&port);
  317.       strncat(_adr,adr,(int) (a - adr));
  318.     } else
  319.       strcpy(_adr,adr);
  320.     
  321.     // rΘcupΘrer adresse rΘsolue
  322.     strcpy(back->info,"host name");
  323.     hp = hts_gethostbyname(_adr, &fullhostent_buffer);
  324.     if (hp == NULL) {
  325.       strcpy(back->r.msg,"Unable to get server's address");
  326.       back->status=FTP_STATUS_READY;    // fini
  327.       back->r.statuscode=-5;
  328.       _HALT_FTP
  329.         return 0;
  330.     }
  331.     _CHECK_HALT_FTP;
  332.     
  333.     // copie adresse
  334.     SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length);
  335.     // copie adresse pour cnx data
  336.     SOCaddr_copyaddr(server_data, server_data_size, hp->h_addr_list[0], hp->h_length);
  337.     // memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
  338.     
  339.     // crΘer ("attachement") une socket (point d'accΦs) internet,en flot
  340.     soc_ctl=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
  341.     if (soc_ctl==INVALID_SOCKET) {
  342.       strcpy(back->r.msg,"Unable to create a socket");
  343.       back->status=FTP_STATUS_READY;    // fini
  344.       back->r.statuscode=-1;
  345.       _HALT_FTP
  346.         return 0;
  347.     }
  348.  
  349.     SOCaddr_initport(server, port);
  350.     // server.sin_port = htons((unsigned short int) port);
  351.     
  352.     // connexion (bloquante, on est en thread)
  353.     strcpy(back->info,"connect");
  354.  
  355. #if HTS_WIN
  356.     if (connect(soc_ctl, (const struct sockaddr FAR *)&server, server_size) != 0) {
  357. #else
  358.       if (connect(soc_ctl, (struct sockaddr *)&server, server_size) == -1) {
  359. #endif
  360.         strcpy(back->r.msg,"Unable to connect to the server");
  361.         back->status=FTP_STATUS_READY;    // fini
  362.         back->r.statuscode=-1;
  363.         _HALT_FTP
  364.           return 0;
  365. #if HTS_WIN
  366.       }
  367. #else
  368.     }
  369. #endif
  370.     _CHECK_HALT_FTP;
  371.     
  372.     {
  373.       char line[1024];
  374.       // envoi du login
  375.       
  376.       // --USER--
  377.       get_ftp_line(soc_ctl,line,timeout);    // en tΩte
  378.       _CHECK_HALT_FTP;
  379.       
  380.       if (line[0]=='2') {        // ok, connectΘ
  381.         strcpy(back->info,"login: user");
  382.         sprintf(line,"USER %s",user);
  383.         send_line(soc_ctl,line);
  384.         get_ftp_line(soc_ctl,line,timeout);
  385.         _CHECK_HALT_FTP;      
  386.         if ((line[0]=='3') || (line[0]=='2')) {
  387.           // --PASS--
  388.           strcpy(back->info,"login: pass");
  389.           sprintf(line,"PASS %s",pass);
  390.           send_line(soc_ctl,line);
  391.           get_ftp_line(soc_ctl,line,timeout);
  392.           _CHECK_HALT_FTP;      
  393.           if (line[0]=='2') {  // ok
  394.             // --CWD--
  395.             char* a;
  396.             a=back->url_fil + strlen(back->url_fil)-1;
  397.             while( (a > back->url_fil) && (*a!='/')) a--;
  398.             if (*a == '/') {    // ok repΘrΘ
  399.               char target[1024];
  400.               target[0]='\0';
  401.               strncat(target,back->url_fil,(int) (a - back->url_fil));
  402.               if (strnotempty(target)==0)
  403.                 strcat(target,"/");
  404.               strcpy(back->info,"cwd");
  405.               sprintf(line,"CWD %s",target);
  406.               send_line(soc_ctl,line);
  407.               get_ftp_line(soc_ctl,line,timeout);
  408.               _CHECK_HALT_FTP;      
  409.               if (line[0]=='2') {
  410.                 send_line(soc_ctl,"TYPE I");
  411.                 get_ftp_line(soc_ctl,line,timeout);
  412.                 _CHECK_HALT_FTP;      
  413.                 if (line[0]=='2') {
  414.                   // ok..
  415.                 } else {
  416.                   strcpy(back->r.msg,"TYPE I error");
  417.                   back->status=FTP_STATUS_READY;    // fini
  418.                   back->r.statuscode=-1;
  419.                 }
  420.               } else {
  421.                 sprintf(back->r.msg,"CWD error: %s",linejmp(line));
  422.                 back->status=FTP_STATUS_READY;    // fini
  423.                 back->r.statuscode=-1;
  424.               }    // sinon on est prΩts
  425.             } else {
  426.               strcpy(back->r.msg,"Unexpected ftp error");
  427.               back->status=FTP_STATUS_READY;    // fini
  428.               back->r.statuscode=-1;
  429.             }
  430.             
  431.           } else {
  432.             sprintf(back->r.msg,"Bad password: %s",linejmp(line));
  433.             back->status=FTP_STATUS_READY;    // fini
  434.             back->r.statuscode=-1;
  435.           }
  436.         } else {
  437.           sprintf(back->r.msg,"Bad user name: %s",linejmp(line));
  438.           back->status=FTP_STATUS_READY;    // fini
  439.           back->r.statuscode=-1;
  440.         }
  441.       } else {
  442.         sprintf(back->r.msg,"Connection refused: %s",linejmp(line));
  443.         back->status=FTP_STATUS_READY;    // fini
  444.         back->r.statuscode=-1;
  445.       }
  446.      
  447.       // ok, si on est prΩts on Θcoute sur un port et on demande la sauce
  448.       if (back->r.statuscode != -1) {
  449.  
  450.         
  451.         //
  452.         // PrΘ-REST
  453.         //
  454. #if FTP_PASV
  455.         if (SOCaddr_getproto(server, server_size) == '1') {
  456.           strcpy(back->info,"pasv");
  457.           sprintf(line,"PASV");
  458.           send_line(soc_ctl,line);
  459.           get_ftp_line(soc_ctl,line,timeout);
  460.         } else { /* ipv6 */
  461.           line[0]='\0';
  462.         }
  463.         _CHECK_HALT_FTP;      
  464.         if (line[0]=='2') {
  465.           char *a,*b,*c;
  466.           a=strchr(line,'(');       // exemple: 227 Entering Passive Mode (123,45,67,89,177,27)
  467.           if (a) {
  468.            
  469.             // -- analyse de l'adresse IP et du port --
  470.             a++;
  471.             b=strchr(a,',');
  472.             if (b) b=strchr(b+1,',');
  473.             if (b) b=strchr(b+1,',');
  474.             if (b) b=strchr(b+1,',');
  475.             c=a; while( (c=strchr(c,',')) ) *c='.';        // remplacer , par .
  476.             if (b) *b='\0';
  477.             //
  478.             strcpy(adr_ip,a);       // copier adresse ip
  479.             //
  480.             if (b) {
  481.               a=b+1;  // dΘbut du port
  482.               b=strchr(a,'.');
  483.               if (b) {
  484.                 int n1,n2;
  485.                 //
  486.                 *b='\0';
  487.                 b++;
  488.                 c=strchr(b,')');
  489.                 if (c) {
  490.                   *c='\0';
  491.                   if ( (sscanf(a,"%d",&n1)==1) && (sscanf(b,"%d",&n2)==1) && (strlen(adr_ip)<=16)) {
  492.                     port_pasv=n2+(n1<<8);
  493.                   }
  494.                 } else {
  495.                   deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  496.                 }    // sinon on est prΩts
  497.               }
  498.             }
  499.             // -- fin analyse de l'adresse IP et du port --
  500.           } else {
  501.             sprintf(back->r.msg,"PASV incorrect: %s",linejmp(line));
  502.             back->status=FTP_STATUS_READY;    // fini
  503.             back->r.statuscode=-1;
  504.           }    // sinon on est prΩts
  505.         } else {
  506.           /*
  507.             * try epsv (ipv6) *
  508.           */
  509.           strcpy(back->info,"pasv");
  510.           sprintf(line,"EPSV");
  511.           send_line(soc_ctl,line);
  512.           get_ftp_line(soc_ctl,line,timeout);
  513.           _CHECK_HALT_FTP;      
  514.           if (line[0]=='2') { /* got it */
  515.             char *a;
  516.             a=strchr(line,'(');       // exemple: 229 Entering Extended Passive Mode (|||6446|)
  517.             if (
  518.               (a != NULL)
  519.               &&
  520.               (*a == '(') 
  521.               && (*(a+1))
  522.               && (*(a+1) == *(a+2)) && (*(a+1) == *(a+3))
  523.               && (isdigit(*(a+4)))
  524.               && (*(a+5))
  525.               ) {
  526.               unsigned int n1 = 0;
  527.               if (sscanf(a+4,"%d",&n1)==1) {
  528.                 if ((n1 < 65535) && (n1 > 0)) {
  529.                   port_pasv=n1;
  530.                 }
  531.               }
  532.             } else {
  533.               sprintf(back->r.msg,"EPSV incorrect: %s",linejmp(line));
  534.               back->status=FTP_STATUS_READY;    // fini
  535.               back->r.statuscode=-1;
  536.             }
  537.           } else {
  538.             sprintf(back->r.msg,"PASV/EPSV error: %s",linejmp(line));
  539.             back->status=FTP_STATUS_READY;    // fini
  540.             back->r.statuscode=-1;
  541.           }    // sinon on est prΩts
  542.         }
  543. #else
  544.         // rien α faire avant
  545. #endif
  546.           
  547. #if FTP_PASV
  548.         if (port_pasv) {
  549. #endif
  550.           // SIZE
  551.           if (back->r.statuscode != -1) {
  552.             if (!transfer_list) {
  553.               char* ua=unescape_http(ftp_filename);
  554.               if (
  555.                 (strchr(ua, ' '))
  556.                 ||
  557.                 (strchr(ua, '\"'))
  558.                 ||
  559.                 (strchr(ua, '\''))
  560.                 ) {
  561.                 sprintf(line,"SIZE \"%s\"", ua);
  562.               } else {
  563.                 sprintf(line,"SIZE %s", ua);
  564.               }
  565.               
  566.               // SIZE?
  567.               strcpy(back->info,"size");
  568.               send_line(soc_ctl,line);
  569.               get_ftp_line(soc_ctl,line,timeout);
  570.               _CHECK_HALT_FTP;      
  571.               if (line[0]=='2') {  // SIZE compris, ALORS tester REST (sinon pas tester: cf probleme des txt.gz decompresses a la volee)
  572.                 // REST?
  573.                 if (fexist(back->url_sav) && (transfer_list==0)) {
  574.                   strcpy(back->info,"rest");
  575.                   sprintf(line,"REST "LLintP,(LLint)fsize(back->url_sav));
  576.                   send_line(soc_ctl,line);
  577.                   get_ftp_line(soc_ctl,line,timeout);
  578.                   _CHECK_HALT_FTP;      
  579.                   if ((line[0]=='3') || (line[0]=='2')) {  // ok
  580.                     rest_understood=1;
  581.                   } // sinon tant pis 
  582.                 } 
  583.               }  // sinon tant pis 
  584.             }
  585.           }
  586. #if FTP_PASV
  587.         }
  588. #endif
  589.  
  590.         //
  591.         // Post-REST
  592.         //
  593. #if FTP_PASV
  594.         // Ok, se connecter
  595.         if (port_pasv) {
  596.           SOCaddr server;
  597.           int server_size=sizeof(server);
  598.           t_hostent* hp;    
  599.           // effacer structure
  600.           memset(&server, 0, sizeof(server));
  601.           
  602.           // infos
  603.           strcpy(back->info,"resolv");
  604.           
  605.           // rΘsoudre
  606.           if (adr_ip[0]) {
  607.             hp = hts_gethostbyname(adr_ip, &fullhostent_buffer);
  608.             if (hp) {
  609.               SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length);
  610.             } else {
  611.               server_size=0;
  612.             }
  613.           } else {
  614.             memcpy(&server, &server_data, sizeof(server_data));
  615.             server_size=server_data_size;
  616.           }
  617.           
  618.           // infos
  619.           strcpy(back->info,"cnxdata");
  620. #if FTP_DEBUG
  621.           printf("Data: Connecting to %s:%d...\n", adr_ip, port_pasv);
  622. #endif
  623.           if (server_size > 0) {
  624.             // socket
  625.             soc_dat=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
  626.             if (soc_dat != INVALID_SOCKET) {
  627.               // structure: connexion au domaine internet, port 80 (ou autre)
  628.               SOCaddr_initport(server, port_pasv);
  629.               // server.sin_port = htons((unsigned short int) port_pasv);
  630. #if HTS_WIN
  631.               if (connect(soc_dat, (const struct sockaddr FAR *)&server, server_size) == 0) {
  632. #else
  633.               if (connect(soc_dat, (struct sockaddr *)&server, server_size) != -1) {
  634. #endif
  635.                 strcpy(back->info,"retr");
  636.                 strcpy(line,line_retr);
  637.                 send_line(soc_ctl,line);
  638.                 get_ftp_line(soc_ctl,line,timeout);
  639.                 _CHECK_HALT_FTP;      
  640.                 if (line[0]=='1') {
  641.                   // OK
  642.                 } else {
  643.                   deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  644.                   //
  645.                   sprintf(back->r.msg,"RETR command errror: %s",linejmp(line));
  646.                   back->status=FTP_STATUS_READY;    // fini
  647.                   back->r.statuscode=-1;
  648.                 }    // sinon on est prΩts
  649.               } else {
  650. #if FTP_DEBUG
  651.                 printf("Data: unable to connect\n");
  652. #endif
  653.                 deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  654.                 //
  655.                 strcpy(back->r.msg,"Unable to connect");
  656.                 back->status=FTP_STATUS_READY;    // fini
  657.                 back->r.statuscode=-1;
  658.               }    // sinon on est prΩts
  659.             } else {
  660.               strcpy(back->r.msg,"Unable to create a socket");
  661.               back->status=FTP_STATUS_READY;    // fini
  662.               back->r.statuscode=-1;
  663.             }    // sinon on est prΩts
  664.           } else {
  665.             sprintf(back->r.msg,"Unable to resolve IP %s",adr_ip);
  666.             back->status=FTP_STATUS_READY;    // fini
  667.             back->r.statuscode=-1;
  668.           }    // sinon on est prΩts
  669.         } else {
  670.           sprintf(back->r.msg,"PASV incorrect: %s",linejmp(line));
  671.           back->status=FTP_STATUS_READY;    // fini
  672.           back->r.statuscode=-1;
  673.         }    // sinon on est prΩts
  674. #else
  675.         //T_SOC soc_servdat;
  676.         strcpy(back->info,"listening");
  677.         if ( (soc_servdat = get_datasocket(line)) != INVALID_SOCKET) {
  678.           _CHECK_HALT_FTP;      
  679.           send_line(soc_ctl,line);          // envoi du RETR
  680.           get_ftp_line(soc_ctl,line,timeout);
  681.           _CHECK_HALT_FTP;      
  682.           if (line[0]=='2') {  // ok
  683.             strcpy(back->info,"retr");
  684.             strcpy(line,line_retr);
  685.             send_line(soc_ctl,line);
  686.             get_ftp_line(soc_ctl,line,timeout);
  687.             _CHECK_HALT_FTP;      
  688.             if (line[0]=='1') {
  689.               //T_SOC soc_dat;
  690.               struct sockaddr dummyaddr;
  691.               int dummylen = sizeof(struct sockaddr);
  692.               if ( (soc_dat=accept(soc_servdat,&dummyaddr,&dummylen)) == INVALID_SOCKET) {
  693.                 strcpy(back->r.msg,"Unable to accept connection");
  694.                 back->status=FTP_STATUS_READY;    // fini
  695.                 back->r.statuscode=-1;
  696.               }
  697.             } else {
  698.               sprintf(back->r.msg,"RETR command errror: %s",linejmp(line));
  699.               back->status=FTP_STATUS_READY;    // fini
  700.               back->r.statuscode=-1;
  701.             }
  702.           } else {
  703.             sprintf(back->r.msg,"PORT command error: %s",linejmp(line));
  704.             back->status=FTP_STATUS_READY;    // fini
  705.             back->r.statuscode=-1;
  706.           }
  707. #if HTS_WIN
  708.           closesocket(soc_servdat);
  709. #else
  710.           close(soc_servdat);
  711. #endif
  712.         } else {
  713.           strcpy(back->r.msg,"Unable to listen to a port");
  714.           back->status=FTP_STATUS_READY;    // fini
  715.           back->r.statuscode=-1;
  716.         }
  717. #endif
  718.         
  719.         //
  720.         // Ok, connexion initiΘe
  721.         //
  722.         if (soc_dat != INVALID_SOCKET) {
  723.           if (rest_understood) {         // REST envoyΘe et comprise
  724.             filenote(back->url_sav,NULL);
  725.             back->r.fp = fopen(fconv(back->url_sav),"ab");
  726.           } else
  727.             back->r.fp = filecreate(back->url_sav);
  728.           strcpy(back->info,"receiving");
  729.           if (back->r.fp != NULL) {
  730.             char buff[1024];
  731.             int len=1;
  732.             int read_len=1024;
  733.             //HTS_TOTAL_RECV_CHECK(read_len);         // Diminuer au besoin si trop de donnΘes reτues
  734.             
  735.             while( (len>0) && (!stop_ftp(back)) ) {
  736.               // attendre les donnΘes
  737.               len=1;    // pas d'erreur pour le moment
  738.               switch(wait_socket_receive(soc_dat,timeout)) {
  739.               case -1:
  740.                 strcpy(back->r.msg,"Read error");
  741.                 back->status=FTP_STATUS_READY;    // fini
  742.                 back->r.statuscode=-1;
  743.                 len=0;    // fin
  744.                 break;
  745.               case 0:
  746.                 sprintf(back->r.msg,"Time out (%d)",timeout);
  747.                 back->status=FTP_STATUS_READY;    // fini
  748.                 back->r.statuscode=-1;
  749.                 len=0;    // fin
  750.                 break;
  751.               }
  752.               
  753.               // rΘception
  754.               if (len) {
  755.                 len=recv(soc_dat,buff,read_len,0);
  756.                 if (len>0) {
  757.                   back->r.size+=len;
  758.                   HTS_STAT.HTS_TOTAL_RECV+=len; 
  759.                   if (back->r.fp) {
  760.                     if ((int) fwrite(buff,1,len,back->r.fp) != len) {
  761.                       strcpy(back->r.msg,"Write error");
  762.                       back->status=FTP_STATUS_READY;    // fini
  763.                       back->r.statuscode=-1;
  764.                       len=0;  // error
  765.                     }
  766.                   } else {
  767.                     strcpy(back->r.msg,"Unexpected write error");
  768.                     back->status=FTP_STATUS_READY;    // fini
  769.                     back->r.statuscode=-1;
  770.                   }
  771.                 } else {        // Erreur ou terminΘ
  772.                   //strcpy(back->r.msg,"Read error");
  773.                   back->status=FTP_STATUS_READY;    // fini
  774.                   back->r.statuscode=0;
  775.                 }
  776.                 read_len=1024; 
  777.                 //HTS_TOTAL_RECV_CHECK(read_len);         // Diminuer au besoin si trop de donnΘes reτues
  778.               }
  779.             }
  780.             if (back->r.fp) { 
  781.               fclose(back->r.fp); 
  782.               back->r.fp=NULL;
  783.             }
  784.           } else {
  785.             strcpy(back->r.msg,"Unable to write file");
  786.             back->status=FTP_STATUS_READY;    // fini
  787.             back->r.statuscode=-1;
  788.           }
  789. #if HTS_WIN
  790.           closesocket(soc_dat);
  791. #else
  792.           close(soc_dat);
  793. #endif
  794.           
  795.           // 226 Transfer complete?
  796.           if (back->r.statuscode != -1) {
  797.             if (wait_socket_receive(soc_ctl,timeout_onfly)>0) {
  798.               // rΘcupΘrer 226 transfer complete
  799.               get_ftp_line(soc_ctl,line,timeout);
  800.               if (line[0]=='2') {       // OK
  801.                 strcpy(back->r.msg,"OK");
  802.                 back->status=FTP_STATUS_READY;    // fini
  803.                 back->r.statuscode=200;
  804.               } else {
  805.                 sprintf(back->r.msg,"RETR incorrect: %s",linejmp(line));
  806.                 back->status=FTP_STATUS_READY;    // fini
  807.                 back->r.statuscode=-1;
  808.               }
  809.             } else {
  810.               strcpy(back->r.msg,"Read error");
  811.               back->status=FTP_STATUS_READY;    // fini
  812.               back->r.statuscode=-1;
  813.             }
  814.           }
  815.           
  816.         }
  817.         
  818.         
  819.         
  820.       }
  821.       
  822.       
  823.     }
  824.     
  825.     _CHECK_HALT_FTP;
  826.     strcpy(back->info,"quit");
  827.     send_line(soc_ctl,"QUIT");    // bye bye
  828.     get_ftp_line(soc_ctl,NULL,timeout);
  829. #if HTS_WIN
  830.     closesocket(soc_ctl);
  831. #else
  832.     close(soc_ctl);
  833. #endif
  834.   }
  835.   
  836.   if (back->r.statuscode!=-1) {
  837.     back->r.statuscode=200;
  838.     strcpy(back->r.msg,"OK");
  839.   }
  840.   back->status=FTP_STATUS_READY;    // fini
  841.   return 0;
  842. }
  843.  
  844.  
  845.  
  846. // ouverture d'un port
  847. T_SOC get_datasocket(char* to_send) {
  848.   T_SOC soc = INVALID_SOCKET;
  849.   char h_loc[256+2];
  850.   
  851.   to_send[0]='\0';
  852.   if (gethostname(h_loc,256)==0) {    // host name
  853.     SOCaddr server;
  854.     int server_size=sizeof(server);
  855.     t_hostent* hp_loc;
  856.     t_fullhostent buffer;
  857.  
  858.     // effacer structure
  859.     memset(&server, 0, sizeof(server));
  860.  
  861.     if ( (hp_loc=vxgethostbyname(h_loc, &buffer)) ) {  // notre host
  862.  
  863.       // copie adresse
  864.       SOCaddr_copyaddr(server, server_size, hp_loc->h_addr_list[0], hp_loc->h_length);
  865.  
  866.       if ( (soc=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0)) != INVALID_SOCKET) {
  867.  
  868.         if ( bind(soc,(struct sockaddr*) &server, server_size) == 0 ) {
  869.           SOCaddr server2;
  870.           int len;
  871.           len=sizeof(server2);
  872.           // effacer structure
  873.           memset(&server2, 0, sizeof(server2));
  874.           if (getsockname(soc,(struct sockaddr*) &server2, &len) == 0) {
  875.             // *port=ntohs(server.sin_port);  // rΘcupΘrer port
  876.             if (listen(soc,10)>=0) {    // au pif le 10
  877. #if HTS_INET6==0
  878.               unsigned short int a,n1,n2;
  879.               // calculer port
  880.               a  = SOCaddr_sinport(server2);
  881.               n1 = (a & 0xff);
  882.               n2 = ((a>>8) & 0xff);
  883.               {
  884.                 char dots[256+2];
  885.                 char dot[256+2];
  886.                 char* a;
  887.                 SOCaddr_inetntoa(dot, 256, server2, sizeof(server2));
  888.                 //
  889.                 dots[0]='\0';
  890.                 strncat(dots, dot, 128);
  891.                 while( (a=strchr(dots,'.')) ) *a=',';    // virgules!
  892.                 while( (a=strchr(dots,':')) ) *a=',';    // virgules!
  893.                 sprintf(to_send,"PORT %s,%d,%d",dots,n1,n2);  
  894.               }
  895. #else
  896.               /*
  897.                 EPRT |1|132.235.1.2|6275|
  898.                 EPRT |2|1080::8:800:200C:417A|5282|
  899.               */
  900.               {
  901.                 char dot[256+2];
  902.                 SOCaddr_inetntoa(dot, 256, server2, len);
  903.                 sprintf(to_send,"EPRT |%c|%s|%d|", SOCaddr_getproto(server2, len), dot, SOCaddr_sinport(server2));  
  904.               }
  905. #endif
  906.               
  907.             } else {
  908. #if HTS_WIN
  909.               closesocket(soc);
  910. #else
  911.               close(soc);
  912. #endif
  913.               soc=INVALID_SOCKET;
  914.             }
  915.             
  916.             
  917.           } else {
  918. #if HTS_WIN
  919.             closesocket(soc);
  920. #else
  921.             close(soc);
  922. #endif
  923.             soc=INVALID_SOCKET;
  924.           }
  925.           
  926.           
  927.         } else {
  928. #if HTS_WIN
  929.           closesocket(soc);
  930. #else
  931.           close(soc);
  932. #endif
  933.           soc=INVALID_SOCKET;
  934.         }
  935.       }
  936.     }
  937.   }
  938.   
  939.   
  940.   return soc;
  941. }
  942.  
  943. #if FTP_DEBUG
  944. FILE* dd=NULL;
  945. #endif
  946.  
  947. // routines de rΘception/Θmission
  948. // 0 = ERROR
  949. int send_line(T_SOC soc,char* data) {
  950.   char line[1024];
  951.   if (_DEBUG_HEAD) {
  952.     if (ioinfo) {
  953.       fprintf(ioinfo,"---> %s\x0d\x0a",data);
  954.       fflush(ioinfo);
  955.     }
  956.   }
  957. #if FTP_DEBUG
  958.   if (dd == NULL) dd = fopen("toto.txt","w");
  959.   fprintf(dd,"---> %s\x0d\x0a",data); fflush(dd);
  960.   printf("---> %s",data); fflush(stdout);
  961. #endif
  962.   sprintf(line,"%s\x0d\x0a",data);
  963.   if (check_socket_connect(soc) != 1) {
  964. #if FTP_DEBUG
  965.     printf("!SOC WRITE ERROR\n");
  966. #endif
  967.     return 0;    // erreur, plus connectΘ!
  968.   }
  969. #if FTP_DEBUG
  970.   {
  971.     int r = (send(soc,line,strlen(line),0) == (int) strlen(line));
  972.     printf("%s\x0d\x0a",data); fflush(stdout);
  973.     return r;
  974.   }
  975. #else
  976.   return (send(soc,line,strlen(line),0) == (int) strlen(line));
  977. #endif
  978. }
  979.  
  980. int get_ftp_line(T_SOC soc,char* line,int timeout) {
  981.   char data[1024];
  982.   int i,ok,multiline;
  983. #if FTP_DEBUG
  984.   if (dd == NULL) dd = fopen("toto.txt","w");
  985. #endif
  986.   
  987.   data[0]='\0';
  988.   i=ok=multiline=0; data[3]='\0';
  989.   do {
  990.     char b;                        
  991.     
  992.     // vΘrifier donnΘes
  993.     switch(wait_socket_receive(soc,timeout)) {
  994.     case -1:   // erreur de lecture
  995.       if (line) strcpy(line,"500 *read error");
  996.       return 0;
  997.       break;
  998.     case 0:
  999.       if (line) sprintf(line,"500 *read timeout (%d)",timeout);
  1000.       return 0;
  1001.       break;
  1002.     }
  1003.     
  1004.     //HTS_TOTAL_RECV_CHECK(dummy);     // Diminuer au besoin si trop de donnΘes reτues
  1005.     switch(recv(soc,&b,1,0)) {
  1006.       //case 0: break;    // pas encore --> erreur (on attend)!
  1007.     case 1:
  1008.       HTS_STAT.HTS_TOTAL_RECV+=1; // compter flux entrant
  1009.       if ((b!=10) && (b!=13))
  1010.         data[i++]=b;
  1011.       break;
  1012.     default:
  1013.       if (line) strcpy(line,"500 *read error");
  1014.       return 0; // error
  1015.       break;
  1016.     }
  1017.     if ( ((b==13) || (b==10)) && (i>0) ){    // CR/LF
  1018.       if (
  1019.         (data[3] == '-')
  1020.         ||
  1021.         ((multiline) && (!isdigit(data[0]))) 
  1022.         )
  1023.       {
  1024.         data[3]='\0';
  1025.         i=0;
  1026.         multiline=1;
  1027.       }
  1028.       else
  1029.         ok=1;    // sortir
  1030.     }
  1031.   } while(!ok);
  1032.   data[i++]='\0';
  1033.   
  1034.   if (_DEBUG_HEAD) {
  1035.     if (ioinfo) {
  1036.       fprintf(ioinfo,"<--- %s\x0d\x0a",data);
  1037.       fflush(ioinfo);
  1038.     }
  1039.   }
  1040. #if FTP_DEBUG
  1041.   fprintf(dd,"<--- %s\n",data); fflush(dd);
  1042.   printf("<--- %s\n",data);
  1043. #endif
  1044.   if (line) strcpy(line,data);
  1045.   return (strnotempty(data));
  1046. }
  1047.  
  1048. // sauter NNN
  1049. char* linejmp(char* line) {
  1050.   if (strlen(line)>4)
  1051.     return line+4;
  1052.   else
  1053.     return line;
  1054. }
  1055.  
  1056. // test socket:
  1057. // 0 : no data
  1058. // 1 : data detected
  1059. // -1: error
  1060. int check_socket(T_SOC soc) {
  1061.   fd_set fds,fds_e;           // poll structures
  1062.   struct timeval tv;          // structure for select
  1063.   FD_ZERO(&fds);
  1064.   FD_ZERO(&fds_e); 
  1065.   // socket read 
  1066.   FD_SET(soc,&fds);           
  1067.   // socket error
  1068.   FD_SET(soc,&fds_e);
  1069.   tv.tv_sec=0;
  1070.   tv.tv_usec=0;
  1071.   // poll!     
  1072.   select(soc + 1,&fds,NULL,&fds_e,&tv);
  1073.   if (FD_ISSET(soc,&fds_e)) {  // error detected
  1074.     return -1;
  1075.   } else if (FD_ISSET(soc,&fds)) {
  1076.     return 1;
  1077.   }
  1078.   return 0;
  1079. }
  1080. // check if connected
  1081. int check_socket_connect(T_SOC soc) {
  1082.   fd_set fds,fds_e;           // poll structures
  1083.   struct timeval tv;          // structure for select
  1084.   FD_ZERO(&fds);
  1085.   FD_ZERO(&fds_e); 
  1086.   // socket write 
  1087.   FD_SET(soc,&fds);           
  1088.   // socket error
  1089.   FD_SET(soc,&fds_e);
  1090.   tv.tv_sec=0;
  1091.   tv.tv_usec=0;
  1092.   // poll!     
  1093.   select(soc + 1,NULL,&fds,&fds_e,&tv);
  1094.   if (FD_ISSET(soc,&fds_e)) {  // error detected
  1095.     return -1;
  1096.   } else if (FD_ISSET(soc,&fds)) {
  1097.     return 1;
  1098.   }
  1099.   return 0;
  1100. }
  1101. // attendre des donnΘes
  1102. int wait_socket_receive(T_SOC soc,int timeout) {
  1103.   // attendre les donnΘes
  1104.   TStamp ltime=time_local();
  1105.   int r;
  1106. #if FTP_DEBUG
  1107.   printf("\x0dWaiting for data "); fflush(stdout);
  1108. #endif
  1109.   while( (!(r = check_socket(soc))) && ( ((int) ((TStamp) (time_local()-ltime))) < timeout )) {
  1110.     Sleep(100);
  1111. #if FTP_DEBUG
  1112.     printf("."); fflush(stdout);
  1113. #endif
  1114.   }
  1115. #if FTP_DEBUG
  1116.   printf("\x0dreturn: %d\x0d",r); fflush(stdout);
  1117. #endif
  1118.   return r;
  1119. }
  1120.  
  1121.  
  1122. // cancel reτu?
  1123. int stop_ftp(lien_back* back) {
  1124.   if (back->stop_ftp) {
  1125.     strcpy(back->r.msg,"Cancelled by User");
  1126.     back->status=FTP_STATUS_READY;    // fini
  1127.     back->r.statuscode=-1;
  1128.     return 1;
  1129.   }
  1130.   return 0;
  1131. }
  1132.  
  1133.  
  1134.  
  1135.  
  1136.